#ifndef CSE272_LIGHTPATH_H_INCLUDED
#define CSE272_LIGHTPATH_H_INCLUDED

#include "Vector3.h"
#include "Ray.h"


class LightPath
{
public:
    float U[2*MAX_REFLECTIONS];
	float Ux, Uy;
	int m_mode;
	enum {MLS, APPM};
	
    LightPath(int mode)
    {
        m_mode = mode;
        generate();
    }

	void getPosVars(float &ux, float &uy)
	{
		ux = Uy;
		uy = Ux;
	}
	void getDirVars(int depth, float &u1, float &u2)
	{
		depth = std::min(MAX_REFLECTIONS-1, depth);
		u1 = U[2*depth];
		u2 = U[2*depth + 1];
	}

    void generate()
	{
		float sintheta, costheta;
		for(int i=0; i<2*MAX_REFLECTIONS; i++)
		{
			U[i] = Rand::getRand();
		}

		Ux = Rand::getRand();
		Uy = Rand::getRand();
	}

    float mltMutateValue( float value, float minv = 0.0, float maxv = 1.0 )
	{
		float s1 = 1./1024, s2 = 1./64;
		float dv = s2*exp(-log(s2/s1)*Rand::getRand());

		if (Rand::getRand() < 0.5)
		{
			value += dv;
			if (value > maxv)
				value -= (maxv - minv);
		}
		else
		{
			value -= dv;
			if (value < minv)
				value += (maxv - minv);
		}

		return value;
	}

    float appmMutateValue(float value, float mutationSize)
    {
		float du1, du2, u1, sgn;
		do {
			du1 = Rand::getRand();
			du2 = Rand::getRand();
			if (du1 < 0.5)
				sgn = -1;
			else
				sgn = 1;
			u1 = value + sgn * pow(du2, 1 + 1/mutationSize);
		} while (u1 < 0 || 1 < u1);

		return u1;
    }

	void recompute()
	{
	}
	
	void mutate(float other=0)
	{
		if (m_mode == MLS)
		{
			Ux = mltMutateValue(Ux);
			Uy = mltMutateValue(Uy);
			for(int i=0; i<2*MAX_REFLECTIONS; i++)
			{
				U[i] = mltMutateValue(U[i]);
			}
		}
		else // APPM
		{
			Ux = appmMutateValue(Ux, other);
			Uy = appmMutateValue(Uy, other);
			for(int i=0; i<2*MAX_REFLECTIONS; i++)
			{
				U[i] = appmMutateValue(U[i], other);
			}
		}
	}
};


#endif //CSE272_LIGHTPATH_H_INCLUDED
